package com.hnyc.token;

import com.alibaba.fastjson2.JSON;
import com.hnyc.domain.OnlineTokenInfo;
import com.hnyc.domain.ShopeeShopInfo;
import com.hnyc.service.IOnlineTokenInfoService;
import com.hnyc.shopee.domain.AccessTokenResp;
import com.hnyc.shopee.domain.RefreshTokenResp;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 主要用于维护token的可用状态
 *
 * @auther zero
 * @date 2023/3/11
 **/
@Component
@Slf4j
public class TokenManager implements ApplicationContextAware {

    Map<String, ITokenService> tokenService;
    @Resource
    IOnlineTokenInfoService tokenInfoService;

    @Resource
    TokenCache tokenCache;

    @PostConstruct
    public void loadToken() {


    }

    public void getToken(ShopeeShopInfo shop) {
        ITokenService shopeeService = tokenService.get(shop.getPltName());
        if (shop.getOnlineShopId() > 0) {
            AccessTokenResp shopToken = shopeeService.getShopToken(shop.getOnlineCode(), shop.getOnlineShopId());
            if(StringUtils.isNoneEmpty(shopToken.getError())){
                log.info("request token failed:[{}]{}",shopToken.getError(),shopToken.getMsg());
                throw  new RuntimeException("get token failed:"+shopToken.getError());
            }
            // 存储到数据库
            OnlineTokenInfo query = new OnlineTokenInfo();
            query.setPltName(shop.getPltName());
            query.setShopId(shop.getOnlineShopId());
            List<OnlineTokenInfo> t = tokenInfoService.selectOnlineTokenInfoList(query);
            if (t.size() > 0) {
                // update token info
                OnlineTokenInfo existToken = t.get(0);
                existToken.setAccessToken(shopToken.getAccessToken());
                existToken.setTokenAt(new Date());
                existToken.setRefreshToken(shopToken.getRefreshToken());
                existToken.setCreatedAt(new Date());
                existToken.setExpireIn((long) shopToken.getExpireIn());
                existToken.setRefreshtAt(new Date());
                existToken.setRefreshtExpireIn(TimeUnit.DAYS.toSeconds(30));
                existToken.setRefreshtExpireAt(DateUtils.addDays(new Date(), 30));
                existToken.setShopId(shop.getOnlineShopId());
                tokenInfoService.updateOnlineTokenInfo(existToken);
                tokenCache.cacheShopToken(existToken);
            } else {
                // insert token info
                OnlineTokenInfo token = new OnlineTokenInfo();
                token.setAccessToken(shopToken.getAccessToken());
                token.setTokenAt(new Date());
                token.setRefreshToken(shopToken.getRefreshToken());
                token.setCreatedAt(new Date());
                token.setExpireIn((long) shopToken.getExpireIn());
                token.setRefreshtAt(new Date());
                token.setRefreshtExpireIn(TimeUnit.DAYS.toSeconds(30));
                token.setRefreshtExpireAt(DateUtils.addDays(new Date(), 30));
                token.setShopId(shop.getOnlineShopId());
                tokenInfoService.insertOnlineTokenInfo(token);
                tokenCache.cacheShopToken(token);
            }


        } else if (shop.getOnlineAccountId() > 0) {
            AccessTokenResp shopToken = shopeeService.getAccountToken(shop.getOnlineCode(), shop.getOnlineAccountId());
            for (Integer id : shopToken.getShopIdList()) {
                // 存储到数据库
                OnlineTokenInfo query = new OnlineTokenInfo();
                query.setPltName(shop.getPltName());
                query.setShopId(Long.valueOf(id));
                query.setAccountId(shop.getOnlineAccountId());
                List<OnlineTokenInfo> t = tokenInfoService.selectOnlineTokenInfoList(query);
                if (t.size() > 0) {
                    // update token info
                    OnlineTokenInfo existToken = t.get(0);
                    existToken.setAccessToken(shopToken.getAccessToken());
                    existToken.setTokenAt(new Date());
                    existToken.setRefreshToken(shopToken.getRefreshToken());
                    existToken.setCreatedAt(new Date());
                    existToken.setExpireIn((long) shopToken.getExpireIn());
                    existToken.setRefreshtAt(new Date());
                    existToken.setRefreshtExpireIn(TimeUnit.DAYS.toSeconds(30));
                    existToken.setRefreshtExpireAt(DateUtils.addDays(new Date(), 30));
                    existToken.setAccountId(shop.getOnlineAccountId());
                    existToken.setShopId(Long.valueOf(id));
                    tokenInfoService.updateOnlineTokenInfo(existToken);
                    tokenCache.cacheShopToken(existToken);
                } else {
                    // insert token info
                    OnlineTokenInfo token = new OnlineTokenInfo();
                    token.setAccessToken(shopToken.getAccessToken());
                    token.setTokenAt(new Date());
                    token.setRefreshToken(shopToken.getRefreshToken());
                    token.setCreatedAt(new Date());
                    token.setExpireIn((long) shopToken.getExpireIn());
                    token.setRefreshtAt(new Date());
                    token.setRefreshtExpireIn(TimeUnit.DAYS.toSeconds(30));
                    token.setRefreshtExpireAt(DateUtils.addDays(new Date(), 30));
                    token.setAccountId(shop.getOnlineAccountId());
                    token.setShopId(Long.valueOf(id));
                    tokenInfoService.insertOnlineTokenInfo(token);
                    tokenCache.cacheShopToken(token);
                }
            }

            // merchant
            for (Integer id : shopToken.getMerchantIdList()) {
                // 存储到数据库
                OnlineTokenInfo query = new OnlineTokenInfo();
                query.setPltName(shop.getPltName());
                query.setMerchantId(Long.valueOf(id));
                query.setAccountId(shop.getOnlineAccountId());
                List<OnlineTokenInfo> t = tokenInfoService.selectOnlineTokenInfoList(query);
                if (t.size() > 0) {
                    // update token info
                    OnlineTokenInfo existToken = t.get(0);
                    existToken.setAccessToken(shopToken.getAccessToken());
                    existToken.setTokenAt(new Date());
                    existToken.setRefreshToken(shopToken.getRefreshToken());
                    existToken.setCreatedAt(new Date());
                    existToken.setExpireIn((long) shopToken.getExpireIn());
                    existToken.setRefreshtAt(new Date());
                    existToken.setRefreshtExpireIn(TimeUnit.DAYS.toSeconds(30));
                    existToken.setRefreshtExpireAt(DateUtils.addDays(new Date(), 30));
                    existToken.setAccountId(shop.getOnlineAccountId());
                    existToken.setMerchantId(Long.valueOf(id));
                    tokenInfoService.updateOnlineTokenInfo(existToken);
                    tokenCache.cacheMerchantToken(existToken);
                } else {
                    // insert token info
                    OnlineTokenInfo token = new OnlineTokenInfo();
                    token.setAccessToken(shopToken.getAccessToken());
                    token.setTokenAt(new Date());
                    token.setRefreshToken(shopToken.getRefreshToken());
                    token.setCreatedAt(new Date());
                    token.setExpireIn((long) shopToken.getExpireIn());
                    token.setRefreshtAt(new Date());
                    token.setRefreshtExpireIn(TimeUnit.DAYS.toSeconds(30));
                    token.setRefreshtExpireAt(DateUtils.addDays(new Date(), 30));
                    token.setAccountId(shop.getOnlineAccountId());
                    token.setMerchantId(Long.valueOf(id));
                    tokenInfoService.insertOnlineTokenInfo(token);
                    tokenCache.cacheMerchantToken(token);
                }
            }

        } else {
            log.warn("无法判断授权类型：{}", JSON.toJSONString(shop));
        }

    }

    public void refreshToken(String redisKey) {
        log.info("refresh token:{}", redisKey);
        if(!TokenKeyHelper.isTokenKey(redisKey)){
            log.info("{} is not token key, ignore");
            return;
        }
        TokenKeyHelper.ShopeeKeyItem shopeeKeyItem = TokenKeyHelper.keyItem(redisKey);
        OnlineTokenInfo token;
        RefreshTokenResp refreshTokenResp;
        switch (shopeeKeyItem.getTokenOfRole()){
            case "shop":
                token = tokenCache.getShopRefreshToken(shopeeKeyItem.getPltName(), Long.valueOf(shopeeKeyItem.getIdOf()));
                refreshTokenResp= tokenService.get(shopeeKeyItem.getPltName()).refreshShopToken(token.getRefreshToken(),token.getShopId());

                break;
            case "account":

                // fixme not exists account token
                token = tokenCache.getAccountRefreshToken(shopeeKeyItem.getPltName(), Long.valueOf(shopeeKeyItem.getIdOf()));
                 refreshTokenResp = tokenService.get(shopeeKeyItem.getPltName()).refreshAccountToken(token.getRefreshToken(), token.getAccountId());
                break;
            case "merchant":
                token = tokenCache.getAccountRefreshToken(shopeeKeyItem.getPltName(), Long.valueOf(shopeeKeyItem.getIdOf()));
                 refreshTokenResp = tokenService.get(shopeeKeyItem.getPltName()).refreshAccountToken(token.getRefreshToken(), token.getMerchantId());
                break;
            default:
                throw new RuntimeException("判断类型失败：" + JSON.toJSONString(shopeeKeyItem));
        }
        token.setRefreshToken(refreshTokenResp.getRefreshToken());
        token.setTokenAt(new Date());
        token.setAccessToken(refreshTokenResp.getAccessToken());
        token.setUpdatedAt(new Date());
        token.setExpireIn(refreshTokenResp.getExpireIn()-10);
        token.setRefreshtExpireAt(new Date());
        token.setRefreshtExpireIn(TimeUnit.DAYS.toSeconds(30));
        // 更新缓存
        tokenCache.cacheToken(token);
        // 更新数据库
        tokenInfoService.updateOnlineTokenInfo(token);
    }

    @Override
    public void setApplicationContext(ApplicationContext ctx) throws BeansException {
        tokenService = ctx.getBeansOfType(ITokenService.class);
    }
}
